﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xunit;
using MetaSharp.Transformation;

namespace MetaSharp.Transformation.Tests.DataStructures
{
	public class SetTests
	{
		[Fact]
		public void CanGetSuccessfully()
		{
			var s = Set<int, int>.Empty
				.Add(1, 11)
				.Add(2, 22)
				.Add(3, 33);

			Assert.Equal(11, s[1].Single());
			Assert.Equal(22, s[2].Single());
			Assert.Equal(33, s[3].Single());
		}

		[Fact]
		public void LLCase()
		{
			var s = Set<int, int>.Empty
				.Add(5, 1)
				.Add(4, 2)
				.Add(3, 3);

			Assert.Equal(4, s.Root.Root.Key);
			Assert.Equal(3, s.Root.Left.Root.Key);
			Assert.Equal(5, s.Root.Right.Root.Key);
		}

		[Fact]
		public void TreeRemainsBalancedAfterUnbalancedInsertIntoBalancedTree()
		{
			var s = Set<int, int>.Empty
				.Add(5, 1)
				.Add(4, 2)
				.Add(3, 3)
				.Add(2, 4)
				.Add(1, 5);

			Assert.Equal(4, s.Root.Root.Key);
			Assert.Equal(2, s.Root.Left.Root.Key);
			Assert.Equal(1, s.Root.Left.Left.Root.Key);
			Assert.Equal(3, s.Root.Left.Right.Root.Key);
			Assert.Equal(5, s.Root.Right.Root.Key);
		}

		[Fact]
		public void LRCase()
		{
			var s = Set<int, int>.Empty
				.Add(5, 1)
				.Add(3, 2)
				.Add(4, 3);

			Assert.Equal(4, s.Root.Root.Key);
			Assert.Equal(3, s.Root.Left.Root.Key);
			Assert.Equal(5, s.Root.Right.Root.Key);
		}

		[Fact]
		public void RRCase()
		{
			var s = Set<int, int>.Empty
				.Add(3, 1)
				.Add(4, 2)
				.Add(5, 3);

			Assert.Equal(4, s.Root.Root.Key);
			Assert.Equal(3, s.Root.Left.Root.Key);
			Assert.Equal(5, s.Root.Right.Root.Key);
		}

		[Fact]
		public void RLCase()
		{
			var s = Set<int, int>.Empty
				.Add(3, 1)
				.Add(5, 2)
				.Add(4, 3);

			Assert.Equal(4, s.Root.Root.Key);
			Assert.Equal(3, s.Root.Left.Root.Key);
			Assert.Equal(5, s.Root.Right.Root.Key);
		}

        [Fact]
        public void SameKeyCase()
        {
            var s = Set<int, int>.Empty
                .Add(1, 2)
                .Add(1, 3)
                .Add(1, 4);

            var r = s[1].ToArray();
            Assert.Equal(1, r.Length);
            Assert.Equal(4, r[0]);
        }

        [Fact]
        public void CollidingButNotEqualKeyCase()
        {
            var s = Set<TestKey, int>.Empty
                .Add(new TestKey { Key = 2 }, 2)
                .Add(new TestKey { Key = 3 }, 3)
                .Add(new TestKey { Key = 4 }, 4);

            Assert.Equal(2, s[new TestKey { Key = 2 }].Single());
            Assert.Equal(3, s[new TestKey { Key = 3 }].Single());
            Assert.Equal(4, s[new TestKey { Key = 4 }].Single());
        }

        [Fact]
        public void CollidingAndEqualKeyCase()
        {
            var s = Set<TestKey, int>.Empty
                .Add(new TestKey { Key = 3 }, 1)
                .Add(new TestKey { Key = 3 }, 2);

            Assert.Equal(1, s[new TestKey { Key = 3 }].Count());
        }

        [Fact]
        public void CollidingAndEqualKeyDoesNotAffectNonEquivalentItemsInBucket()
        {
            var s = Set<TestKey, int>.Empty
                .Add(new TestKey { Key = 2 }, 2)
                .Add(new TestKey { Key = 3 }, 3)
                .Add(new TestKey { Key = 4 }, 4)
                .Add(new TestKey { Key = 3 }, 5);

            Assert.Equal(2, s[new TestKey { Key = 2 }].Single());
            Assert.Equal(5, s[new TestKey { Key = 3 }].Single());
            Assert.Equal(4, s[new TestKey { Key = 4 }].Single());
        }

        class TestKey
        {
            public int Key { get; set; }

            public override int GetHashCode()
            {
                return 1;
            }

            public override bool Equals(object obj)
            {
                return this.Key.Equals(((TestKey)obj).Key);
            }
        }
	}
}
